<?php

namespace App\Kuafu\Order\Service;

use App\Kuafu\Base\Model\BaseModel;
use App\Kuafu\Category\Model\CategoryModel;
use App\Kuafu\Common\Service\CommonService;
use App\Kuafu\Common\Service\SeparateService;
use App\Kuafu\Config\Service\ConfigService;
use App\Kuafu\CouponExt\Model\OrderCouponExtSplitModel;
use App\Kuafu\CouponPackage\Enum\CouponPackageCodeEnum;
use App\Kuafu\CouponPackage\Enum\CouponPackageEnum;
use App\Kuafu\CouponPackage\Exceptions\CouponPackageException;
use App\Kuafu\CouponPackage\Model\CouponPackageModel;
use App\Kuafu\CouponPackage\Model\CouponPackageOrderModel;
use App\Kuafu\CouponPackage\Model\CouponPackageShopMappingModel;
use App\Kuafu\Customer\Model\CustomerModel;
use App\Kuafu\Guanyuan\Model\ShopDailyWaiMaiRateModel;
use App\Kuafu\Log\Model\OperateLogModel;
use App\Kuafu\Order\Enum\CodeEnum;
use App\Kuafu\Order\Enum\OrderCacheEnum;
use App\Kuafu\Order\Enum\OrderCodeEnum;
use App\Kuafu\Order\Enum\OrderMerchantEnum;
use App\Kuafu\Order\Exceptions\OrderException;
use App\Kuafu\Order\Model\Clickhouse\OrderCHModel;
use App\Kuafu\Order\Model\Clickhouse\OrderDetailCHModel;
use App\Kuafu\Order\Model\Clickhouse\OrderPayUnionCHModel;
use App\Kuafu\Order\Model\OrderCouponSplitModel;
use App\Kuafu\Order\Model\OrderDetailSplitModel;
use App\Kuafu\Order\Model\OrderExternalSplitModel;
use App\Kuafu\Order\Model\OrderModel;
use App\Kuafu\Order\Model\OrderPayUnionSplitModel;
use App\Kuafu\Order\Model\OrderSplitModel;
use App\Kuafu\Pay\Enum\PayCodeEnum;
use App\Kuafu\Pay\Exceptions\PayException;
use App\Kuafu\Pay\Model\PayStreamModel;
use App\Kuafu\Pay\Model\RefundStreamModel;
use App\Kuafu\Pay\Model\ShopPaymentModel;
use App\Kuafu\Product\Enum\ProductCodeEnum;
use App\Kuafu\Product\Exceptions\ProductException;
use App\Kuafu\Product\Model\Product;
use App\Kuafu\Shop\Enum\ShopCodeEnum;
use App\Kuafu\Shop\Exceptions\ShopException;
use App\Kuafu\Shop\Model\Shop;
use App\Kuafu\Shop\Model\ShopDistributionBillRecordModel;
use App\Kuafu\Shop\Model\ShopDistributionModel;
use App\Kuafu\Shop\Service\ShopDistributionService;
use App\Kuafu\Shop\Service\ShopService;
use App\Kuafu\WaiMai\Enum\WaiMaiDBEnum;
use App\Kuafu\WaiMai\Model\Clickhouse\WaiMaiOrderCHModel;
use App\Kuafu\WaiMai\Model\Clickhouse\WaiMaiOrderDetailCHModel;
use App\Kuafu\WaiMai\Model\WaiMaiOrderDetailModel;
use App\Kuafu\WaiMai\Model\WaiMaiOrderModel;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;

/**
 * 商家APP订单统计服务-base
 */
class OrderMerchantBaseService
{
    private $shopIds, $startTime, $endTime;

    /**
     * 是否强制使用某存储引擎
     * @var string|null
     */
    protected ?string $forceEngine = null;

    public function setForceEngine(?string $forceEngine): OrderMerchantBaseService
    {
        $this->forceEngine = $forceEngine;
        return $this;
    }

    /**
     * 实际使用的引擎
     * @var string
     */
    protected string $useEngine;

    protected function setShopStartEndTime(array $shopIds, int $startTime, int $endTime)
    {
        $this->shopIds   = $shopIds;
        $this->startTime = $startTime;
        $this->endTime   = $endTime;

        return $this;
    }

    // 券包订单
    protected function couponPackageOrderBase()
    {
        $orderObj = $this->getModelOrderObj(OrderMerchantEnum::ORDER_TYPE_COUPON_PACKAGE)
                         ->where('payStatus', CouponPackageOrderModel::PAY_STATUS_1);

        // 订单原价
        $originPrice = $orderObj->sum('payPrice');

        // 订单实收
        $incomePrice = $originPrice;

        // 有效订单数
        $orderCount = $orderObj->count();

        $data = [
            OrderMerchantEnum::STAT_ORIGINAL_PRICE => (int)$originPrice,
            OrderMerchantEnum::STAT_INCOME_PRICE   => (int)$incomePrice,
            OrderMerchantEnum::STAT_ORDER_COUNT    => (int)$orderCount,
        ];

        return $data;
    }

    // 券包折线图
    protected function couponPackageOrderStatBase(int $statisticsType)
    {
        $orderObj = $this->getModelOrderObj(OrderMerchantEnum::ORDER_TYPE_COUPON_PACKAGE)
                         ->where('payStatus', CouponPackageOrderModel::PAY_STATUS_1);

        $timeColumn = OrderMerchantEnum::ORDER_TYPE_TIME_COLUMN[OrderMerchantEnum::ORDER_TYPE_COUPON_PACKAGE];

        switch ($statisticsType) {
            case OrderMerchantEnum::STAT_ORIGINAL_PRICE:
                $orderObj->selectRaw("payPrice as num, {$timeColumn} as time");
                break;
            case OrderMerchantEnum::STAT_INCOME_PRICE:
                $orderObj->selectRaw("shopIncomes as num, {$timeColumn} as time");
                break;
            case OrderMerchantEnum::STAT_ORDER_COUNT:
                $orderObj->selectRaw("count(1) as num, {$timeColumn} as time");
                break;
            default:
                return collect();
        }

        return $orderObj->get();

    }


    // 店内订单
    protected function inOrderBase()
    {
        $orderObj = $this->getModelOrderObj(OrderMerchantEnum::ORDER_TYPE_IN)
                         ->where('orderStatus', CodeEnum::ORDER_STATUS_FINISHED)
                         ->where('refundStatus', '!=', CodeEnum::ORDER_REFUND_STATUS_ALL);

        $orderObjSum = $orderObj
            ->when($this->useEngine == SeparateService::DB, function ($query) {
                $query->select([
                    DB::raw('sum(originalPrice) as sumOriginalPrice'),
                    DB::raw('sum(realPayPrice) as sumRealPayPrice'),
                    DB::raw('sum(realDiscountPrice) as sumDiscountPrice'),
                ]);
            })
            ->when($this->useEngine == SeparateService::CLICKHOUSE, function ($query) {
                $query->select([
                    raw('sum(originalPrice) as sumOriginalPrice'),
                    raw('sum(realPayPrice) as sumRealPayPrice'),
                    raw('sum(realDiscountPrice) as sumDiscountPrice'),
                ]);
            })
            ->get()
            ->first();

        // 有效订单数
        $orderCount = $orderObj->count();

        $channelOrderObjSum = $orderObj->where("distributionId", ">", 0)
                                       ->when($this->useEngine == SeparateService::DB, function ($query) {
                                           $query->select([
                                               DB::raw('sum(realPayPrice) as sumRealPayPrice'),
                                               DB::raw('sum(distributionAmount) as sumDistributionAmount'),
                                           ]);
                                       })
                                       ->when($this->useEngine == SeparateService::CLICKHOUSE, function ($query) {
                                           $query->select([
                                               raw('sum(realPayPrice) as sumRealPayPrice'),
                                               raw('sum(distributionAmount) as sumDistributionAmount'),
                                           ]);
                                       })
                                       ->get()
                                       ->first();

        // 营业额
        $originPrice = $orderObjSum->sumOriginalPrice;

        // 营业收入
        $incomePrice = $orderObjSum->sumRealPayPrice;

        // 优惠金额
        $discountPrice = $orderObjSum->sumDiscountPrice;

        // 折前单均
        $beforeDiscountAvgPrice = $orderCount > 0 ? floor($originPrice / $orderCount) : 0;

        // 折后单均
        $afterDiscountAvgPrice = $orderCount > 0 ? floor($incomePrice / $orderCount) : 0;

        $data = [
            OrderMerchantEnum::STAT_ORIGINAL_PRICE              => (int)$originPrice,
            OrderMerchantEnum::STAT_INCOME_PRICE                => (int)$incomePrice,
            OrderMerchantEnum::STAT_DISCOUNT_PRICE              => (int)$discountPrice,
            OrderMerchantEnum::STAT_ORDER_COUNT                 => (int)$orderCount,
            OrderMerchantEnum::STAT_BEFORE_DISCOUNT_AVG_PRICE   => (int)$beforeDiscountAvgPrice,
            OrderMerchantEnum::STAT_AFTER_DISCOUNT_AVG_PRICE    => (int)$afterDiscountAvgPrice,
            OrderMerchantEnum::STAT_MERCHANT_CHANNEL_PAY        => (int)$channelOrderObjSum->sumRealPayPrice,
            OrderMerchantEnum::STAT_MERCHANT_CHANNEL_COMMISSION => (int)$channelOrderObjSum->sumDistributionAmount,
        ];

        return $data;
    }

    // 店内订单的每种统计情况
    protected function inOrderStatBase(int $statisticsType)
    {
        $orderObj = $this->getModelOrderObj(OrderMerchantEnum::ORDER_TYPE_IN)
                         ->where('refundStatus', '!=', CodeEnum::ORDER_REFUND_STATUS_ALL)
                         ->where('orderStatus', CodeEnum::ORDER_STATUS_FINISHED);

        $timeColumn = OrderMerchantEnum::ORDER_TYPE_TIME_COLUMN[OrderMerchantEnum::ORDER_TYPE_IN];

        switch ($statisticsType) {
            case OrderMerchantEnum::STAT_ORIGINAL_PRICE:
            case OrderMerchantEnum::STAT_BEFORE_DISCOUNT_AVG_PRICE:

                $orderObj->when($this->useEngine == SeparateService::DB, function ($query) use ($timeColumn) {
                    $query->select([
                        DB::raw('originalPrice as num'),
                        DB::raw("{$timeColumn} as time"),
                    ]);
                })
                         ->when($this->useEngine == SeparateService::CLICKHOUSE, function ($query) use ($timeColumn) {
                             $query->select([
                                 raw('originalPrice as num'),
                                 raw("{$timeColumn} as time"),
                             ]);
                         });
                break;
            case OrderMerchantEnum::STAT_INCOME_PRICE:
            case OrderMerchantEnum::STAT_AFTER_DISCOUNT_AVG_PRICE:

                $orderObj->when($this->useEngine == SeparateService::DB, function ($query) use ($timeColumn) {
                    $query->select([
                        DB::raw('realPayPrice as num'),
                        DB::raw("{$timeColumn} as time"),
                    ]);
                })
                         ->when($this->useEngine == SeparateService::CLICKHOUSE, function ($query) use ($timeColumn) {
                             $query->select([
                                 raw('realPayPrice as num'),
                                 raw("{$timeColumn} as time"),
                             ]);
                         });

                break;
            case OrderMerchantEnum::STAT_ORDER_COUNT:

                $orderObj->when($this->useEngine == SeparateService::DB, function ($query) use ($timeColumn) {
                    $query->select([
                        DB::raw('1 as num'),
                        DB::raw("{$timeColumn} as time"),
                    ]);
                })
                         ->when($this->useEngine == SeparateService::CLICKHOUSE, function ($query) use ($timeColumn) {
                             $query->select([
                                 raw('1 as num'),
                                 raw("{$timeColumn} as time"),
                             ]);
                         });


                break;
            case OrderMerchantEnum::STAT_DISCOUNT_PRICE:

                $orderObj->when($this->useEngine == SeparateService::DB, function ($query) use ($timeColumn) {
                    $query->select([
                        DB::raw('realDiscountPrice as num'),
                        DB::raw("{$timeColumn} as time"),
                    ]);
                })
                         ->when($this->useEngine == SeparateService::CLICKHOUSE, function ($query) use ($timeColumn) {
                             $query->select([
                                 raw('realDiscountPrice as num'),
                                 raw("{$timeColumn} as time"),
                             ]);
                         });

                break;
            case OrderMerchantEnum::STAT_MERCHANT_CHANNEL_PAY:
                $orderObj->where("distributionId", ">", 0)
                         ->when($this->useEngine == SeparateService::DB, function ($query) use ($timeColumn) {
                             $query->select([
                                 DB::raw('originalPrice as num'),
                                 DB::raw("{$timeColumn} as time"),
                             ]);
                         })
                         ->when($this->useEngine == SeparateService::CLICKHOUSE, function ($query) use ($timeColumn) {
                             $query->select([
                                 raw('originalPrice as num'),
                                 raw("{$timeColumn} as time"),
                             ]);
                         });

                break;
            case OrderMerchantEnum::STAT_MERCHANT_CHANNEL_COMMISSION:
                $orderObj->where("distributionId", ">", 0)
                         ->when($this->useEngine == SeparateService::DB, function ($query) use ($timeColumn) {
                             $query->select([
                                 DB::raw('distributionAmount as num'),
                                 DB::raw("{$timeColumn} as time"),
                             ]);
                         })
                         ->when($this->useEngine == SeparateService::CLICKHOUSE, function ($query) use ($timeColumn) {
                             $query->select([
                                 raw('distributionAmount as num'),
                                 raw("{$timeColumn} as time"),
                             ]);
                         });

                break;
            default:
                throw new OrderException(OrderCodeEnum::ERR_STAT_TYPE);
        }

        return $orderObj->get();
    }

    // 外卖订单
    protected function waiMaiOrderBase(int $sourceType)
    {
        $orderObj = $this->getModelOrderObj(OrderMerchantEnum::ORDER_TYPE_WAI_MAI)
                         ->where("orderStatus", '!=', WaiMaiDBEnum::ORDER_STATUS_7)
                         ->when($sourceType, function ($query) use ($sourceType) {
                             $query->where('sourceType', $sourceType);
                         });


        $orderObjSum = $orderObj
            ->when($this->useEngine == SeparateService::DB, function ($query) {
                $query->select([
                    DB::raw('sum(originalPrice)-sum(originalShippingPrice) as sumOriginalPrice'),
                    DB::raw('sum(expectIncome) as sumExpectIncome'),
                    DB::raw('sum(payPrice) as sumPayPrice'),
                ]);
            })
            ->when($this->useEngine == SeparateService::CLICKHOUSE, function ($query) {
                $query->select([
                    raw('sum(originalPrice)-sum(originalShippingPrice) as sumOriginalPrice'),
                    raw('sum(expectIncome) as sumExpectIncome'),
                    raw('sum(payPrice) as sumPayPrice'),
                ]);
            })
            ->get()
            ->first();

        // 美团营业额 = 原价 - 包装费 - 原始配送费
        $originPrice = $orderObjSum->sumOriginalPrice;

        // 订单实收
        $incomePrice = $orderObjSum->sumExpectIncome;

        // 顾客实付
        $payPrice = $orderObjSum->sumPayPrice;

        // 有效订单数
        $orderCount = $orderObj->count();

        // 到手率
        $incomeRate = $payPrice > 0 && $originPrice > 0 ? bcmul(round($incomePrice / $originPrice, 4), 100, 2) : 0;

        // 折后单均
        $afterDiscountAvgPrice = $orderCount > 0 ? floor($incomePrice / $orderCount) : 0;

        // 外卖评分
        $waiMaiScoreMT = $this->getModelOrderObj(OrderMerchantEnum::ORDER_TYPE_WAIMAI_SCORE)
                              ->where('type', WaiMaiDBEnum::SOURCE_TYPE_MT_WM)
                              ->select(DB::raw('sum(rating) / count(*) as score'))
                              ->get()
                              ->first()['score'] ?? 0;

        $waiMaiScoreELM = $this->getModelOrderObj(OrderMerchantEnum::ORDER_TYPE_WAIMAI_SCORE)
                              ->where('type', WaiMaiDBEnum::SOURCE_TYPE_ELM)
                              ->select(DB::raw('sum(rating) / count(*) as score'))
                              ->get()
                              ->first()['score'] ?? 0;

        $data = [
            OrderMerchantEnum::STAT_ORIGINAL_PRICE           => (int)$originPrice,
            OrderMerchantEnum::STAT_INCOME_PRICE             => (int)$incomePrice,
            OrderMerchantEnum::STAT_PAY_PRICE                => (int)$payPrice,
            OrderMerchantEnum::STAT_ORDER_COUNT              => (int)$orderCount,
            OrderMerchantEnum::STAT_INCOME_RATE              => (float)$incomeRate,
            OrderMerchantEnum::STAT_AFTER_DISCOUNT_AVG_PRICE => (int)$afterDiscountAvgPrice,
            OrderMerchantEnum::STAT_MERCHANT_WAI_MAI_SCORE_MT=> ShopDailyWaiMaiRateModel::formatScore($waiMaiScoreMT),
            OrderMerchantEnum::STAT_MERCHANT_WAI_MAI_SCORE_ELM=> ShopDailyWaiMaiRateModel::formatScore($waiMaiScoreELM),
        ];

        return $data;
    }

    // 外卖订单的每种统计明细
    protected function waiMaiOrderStatBase(int $statisticsType, int $sourceType = 0)
    {
        $orderObj = $this->getModelOrderObj(OrderMerchantEnum::ORDER_TYPE_WAI_MAI)
                         ->where('orderStatus', '!=', WaiMaiDBEnum::ORDER_STATUS_7)
                         ->when($sourceType, function ($query) use ($sourceType) {
                             $query->where('sourceType', $sourceType);
                         });

        $timeColumn = OrderMerchantEnum::ORDER_TYPE_TIME_COLUMN[OrderMerchantEnum::ORDER_TYPE_WAI_MAI];

        switch ($statisticsType) {
            case OrderMerchantEnum::STAT_ORIGINAL_PRICE:
            case OrderMerchantEnum::STAT_BEFORE_DISCOUNT_AVG_PRICE:
                $orderObj
                    ->when($this->useEngine == SeparateService::DB, function ($query) use ($timeColumn) {
                        $query->select([
                            DB::raw('(originalPrice-originalShippingPrice) as num'),
                            DB::raw("{$timeColumn} as time"),
                        ]);
                    })
                    ->when($this->useEngine == SeparateService::CLICKHOUSE, function ($query) use ($timeColumn) {
                        $query->select([
                            raw('(originalPrice-originalShippingPrice) as num'),
                            raw("{$timeColumn} as time"),
                        ]);
                    });

                break;
            case OrderMerchantEnum::STAT_INCOME_PRICE:
            case OrderMerchantEnum::STAT_AFTER_DISCOUNT_AVG_PRICE:

                $orderObj
                    ->when($this->useEngine == SeparateService::DB, function ($query) use ($timeColumn) {
                        $query->select([
                            DB::raw('expectIncome as num'),
                            DB::raw("{$timeColumn} as time"),
                        ]);
                    })
                    ->when($this->useEngine == SeparateService::CLICKHOUSE, function ($query) use ($timeColumn) {
                        $query->select([
                            raw('expectIncome as num'),
                            raw("{$timeColumn} as time"),
                        ]);
                    });

                break;
            case OrderMerchantEnum::STAT_ORDER_COUNT:

                $orderObj
                    ->when($this->useEngine == SeparateService::DB, function ($query) use ($timeColumn) {
                        $query->select([
                            DB::raw('1 as num'),
                            DB::raw("{$timeColumn} as time"),
                        ]);
                    })
                    ->when($this->useEngine == SeparateService::CLICKHOUSE, function ($query) use ($timeColumn) {
                        $query->select([
                            raw('1 as num'),
                            raw("{$timeColumn} as time"),
                        ]);
                    });

                break;
            case OrderMerchantEnum::STAT_PAY_PRICE:

                $orderObj
                    ->when($this->useEngine == SeparateService::DB, function ($query) use ($timeColumn) {
                        $query->select([
                            DB::raw('payPrice as num'),
                            DB::raw("{$timeColumn} as time"),
                        ]);
                    })
                    ->when($this->useEngine == SeparateService::CLICKHOUSE, function ($query) use ($timeColumn) {
                        $query->select([
                            raw('payPrice as num'),
                            raw("{$timeColumn} as time"),
                        ]);
                    });

                break;
            case OrderMerchantEnum::STAT_INCOME_RATE:

                $orderObj
                    ->when($this->useEngine == SeparateService::DB, function ($query) use ($timeColumn) {
                        $query->select([
                            DB::raw('round(expectIncome/(originalPrice-originalShippingPrice), 4)*10000  as num'),
                            DB::raw("{$timeColumn} as time"),
                        ]);
                    })
                    ->when($this->useEngine == SeparateService::CLICKHOUSE, function ($query) use ($timeColumn) {
                        $query->select([
                            raw('round(expectIncome/(originalPrice-originalShippingPrice), 4)*10000  as num'),
                            raw("{$timeColumn} as time"),
                        ]);
                    });

                break;
            case OrderMerchantEnum::STAT_DISCOUNT_PRICE:
                // 优惠金额 = 原价 - 实付
                $orderObj
                    ->when($this->useEngine == SeparateService::DB, function ($query) use ($timeColumn) {
                        $query->select([
                            DB::raw('originalPrice+packingPrice-payPrice as num'),
                            DB::raw("{$timeColumn} as time"),
                        ]);
                    })
                    ->when($this->useEngine == SeparateService::CLICKHOUSE, function ($query) use ($timeColumn) {
                        $query->select([
                            raw('originalPrice+packingPrice-payPrice as num'),
                            raw("{$timeColumn} as time"),
                        ]);
                    });

                break;
            case OrderMerchantEnum::STAT_PLATFORM_PRICE:
                $orderObj
                    ->when($this->useEngine == SeparateService::DB, function ($query) use ($timeColumn) {
                        $query->select([
                            DB::raw('platformPrice as num'),
                            DB::raw("{$timeColumn} as time"),
                        ]);
                    })
                    ->when($this->useEngine == SeparateService::CLICKHOUSE, function ($query) use ($timeColumn) {
                        $query->select([
                            raw('platformPrice as num'),
                            raw("{$timeColumn} as time"),
                        ]);
                    });

                break;
            case OrderMerchantEnum::STAT_MERCHANT_ACT_PRICE:

                $orderObj
                    ->when($this->useEngine == SeparateService::DB, function ($query) use ($timeColumn) {
                        $query->select([
                            DB::raw('activityExpenditure as num'),
                            DB::raw("{$timeColumn} as time"),
                        ]);
                    })
                    ->when($this->useEngine == SeparateService::CLICKHOUSE, function ($query) use ($timeColumn) {
                        $query->select([
                            raw('activityExpenditure as num'),
                            raw("{$timeColumn} as time"),
                        ]);
                    });

                break;

            case OrderMerchantEnum::STAT_MERCHANT_WAI_MAI_SCORE_MT:

                $orderObj = $this->getModelOrderObj(OrderMerchantEnum::ORDER_TYPE_WAIMAI_SCORE)
                                 ->where('type', WaiMaiDBEnum::SOURCE_TYPE_MT_WM)
                                 ->select(DB::raw('UNIX_TIMESTAMP(date) as time'), 'rating as num');

                break;
            case OrderMerchantEnum::STAT_MERCHANT_WAI_MAI_SCORE_ELM:

                $orderObj = $this->getModelOrderObj(OrderMerchantEnum::ORDER_TYPE_WAIMAI_SCORE)
                                 ->where('type', WaiMaiDBEnum::SOURCE_TYPE_ELM)
                                 ->select(DB::raw('UNIX_TIMESTAMP(date) as time'), 'rating as num');

                break;

            default:
                throw new OrderException(OrderCodeEnum::ERR_STAT_TYPE);
        }

        return $orderObj->get();
    }

    // 店内订单列表
    protected function inOrderListsBase(int $pageSize, int $pageNum)
    {
        $orderObj = $this->getModelOrderObj(OrderMerchantEnum::ORDER_TYPE_IN)
                         ->where('orderStatus', CodeEnum::ORDER_STATUS_FINISHED)
                         ->orderByDesc('createdAt');

        $total = $orderObj->count();

//        $query = $orderObj->paginate($pageSize, ['*'], 'page', $pageNum);
        $query = $orderObj->simplePaginate($pageSize, ['*'], 'page', $pageNum);

        $lists = collect($query->items())->map(function ($item) use ($total) {
            $item->timestamps = false;

            return [
                'orderId'         => (string)$item->orderId,
                'createdAt'       => date('Y-m-d H:i:s', $item->createdAt),
                'serialNum'       => str_pad($item->serialNum, CodeEnum::ORDER_LEADING_ZERO, "0", STR_PAD_LEFT),
                'orderStatusText' => $item->orderStatusText,
                'payPrice'        => $item->realPayPrice,
            ];
        });

        return [
            'pageNum'   => $query->currentPage(),
            'pageSize'  => $query->perPage(),
            'pageCount' => ceil($total / $query->perPage()),
            'count'     => $total,
            'lists'     => $lists,
        ];
    }

    // 外卖订单列表
    protected function waiMaiOrderListsBase(int $pageSize, int $pageNum, int $sourceType)
    {
        $orderObj = $this->getModelOrderObj(OrderMerchantEnum::ORDER_TYPE_WAI_MAI)
                         ->when($sourceType, function ($query) use ($sourceType) {
                             $query->where('sourceType', $sourceType);
                         })
                         ->where('orderStatus', '!=', WaiMaiDBEnum::ORDER_STATUS_7)
                         ->orderByDesc('createdAt');

        $total = $orderObj->count();

        $query = $orderObj->simplePaginate($pageSize, ['*'], 'page', $pageNum);

        $lists = collect($query->items())->map(function ($item) {
            $item->timestamps = false;

            return [
                'orderId'         => (string)$item->orderId,
                'createdAt'       => date('Y-m-d H:i:s', $item->createdAt),
                'serialNum'       => str_pad($item->serialNum, CodeEnum::ORDER_LEADING_ZERO, "0", STR_PAD_LEFT),
                'orderStatusText' => $item->orderStatusText,
                'payPrice'        => $item->payPrice,
                'sourceType'      => $item->sourceType,
                'expectIncome'    => $item->expectIncome,
            ];
        });

        return [
            'pageNum'   => $query->currentPage(),
            'pageSize'  => $query->perPage(),
            'pageCount' => ceil($total / $query->perPage()),
            'count'     => $total,
            'lists'     => $lists,
        ];
    }

    /**
     * 获取订单的Model
     * @param int $orderType
     */
    protected function getModelOrderObj(int $orderType)
    {
        $this->useEngine = $this->forceEngine ?: (new SeparateService($this->startTime, $this->endTime))->check();

        // 堂食
        if ($orderType == OrderMerchantEnum::ORDER_TYPE_IN) {

            if ($this->useEngine == SeparateService::DB) {
                $model = OrderSplitModel::suffix($this->shopIds[0]);
            } else {
                $model = OrderCHModel::query();
            }

            return $model
                         ->whereBetween(OrderMerchantEnum::ORDER_TYPE_TIME_COLUMN[$orderType], [$this->startTime, $this->endTime])
                         ->when(true, function ($query) {
                             if (count($this->shopIds) == 1) {
                                 $query->where('shopId', $this->shopIds[0]);
                             } else {
                                 $query->whereIn('shopId', $this->shopIds);
                             }
                         });
        }

        // 外卖
        if ($orderType == OrderMerchantEnum::ORDER_TYPE_WAI_MAI) {

            if ($this->useEngine == SeparateService::DB) {
                $model = WaiMaiOrderModel::suffix($this->shopIds[0]);
            } else {
                $model = WaiMaiOrderCHModel::query();
            }

            return $model
                ->whereBetween(OrderMerchantEnum::ORDER_TYPE_TIME_COLUMN[$orderType],
                    [$this->startTime, $this->endTime])
                ->when(true, function ($query) {
                    if (count($this->shopIds) == 1) {
                        $query->where('shopId', $this->shopIds[0]);
                    } else {
                        $query->whereIn('shopId', $this->shopIds);
                    }
                });
        }

        // 券包
        if ($orderType == OrderMerchantEnum::ORDER_TYPE_COUPON_PACKAGE) {
            return CouponPackageOrderModel::query()
                                          ->whereBetween(OrderMerchantEnum::ORDER_TYPE_TIME_COLUMN[$orderType],
                                              [$this->startTime, $this->endTime])
                                          ->when(true, function ($query) {
                                              if (count($this->shopIds) == 1) {
                                                  $query->where('shopId', $this->shopIds[0]);
                                              } else {
                                                  $query->whereIn('shopId', $this->shopIds);
                                              }
                                          });
        }

        // 分销订单
        if ($orderType == OrderMerchantEnum::ORDER_TYPE_DISTRIBUTION) {

            if ($this->useEngine == SeparateService::DB) {
                $model = OrderSplitModel::suffix($this->shopIds[0]);
            } else {
                $model = OrderCHModel::query();
            }

            return $model
                         ->whereBetween(OrderMerchantEnum::ORDER_TYPE_TIME_COLUMN[$orderType],
                             [$this->startTime, $this->endTime])
                         ->when(true, function ($query) {
                             if (count($this->shopIds) == 1) {
                                 $query->where('shopId', $this->shopIds[0]);
                             } else {
                                 $query->whereIn('shopId', $this->shopIds);
                             }
                         });
        }

        // 外卖评分
        if ($orderType == OrderMerchantEnum::ORDER_TYPE_WAIMAI_SCORE) {

            return ShopDailyWaiMaiRateModel::query()
                                    ->where('rmsShopId', $this->shopIds[0])
//                                    ->where('type', WaiMaiDBEnum::SOURCE_TYPE_MT_WM)
                                    ->whereBetween('date', [date('Y-m-d', $this->startTime), date('Y-m-d', $this->endTime)]);
        }

        return null;
    }

    // 底层的折线图实现
    protected function chartsBase(
        int $startTime,
        int $endTime,
        int $oriEndTime,
        int $interval,
        int $statisticsType,
        int $orderType,
        int $showTimeTab,
        int $sourceType = 0,
        int $vipIn = 0
    ) {

        $cacheKey = OrderCacheEnum::getOrderCharts($this->shopIds[0], $startTime, $oriEndTime, $statisticsType,
            $orderType, $interval, $showTimeTab, $sourceType, $vipIn);

        $cacheData = Cache::get($cacheKey);
        if ($cacheData) {
            return $cacheData;
        }

        $charts = [];

        $order = $this->setShopStartEndTime($this->shopIds, $startTime, $endTime);

        // 店内、店外订单处理
        if ($orderType == OrderMerchantEnum::ORDER_TYPE_IN) {
            $calc = $order->inOrderStatBase($statisticsType)
                          ->toArray();
        } elseif ($orderType == OrderMerchantEnum::ORDER_TYPE_WAI_MAI) {
            $calc = $order->waiMaiOrderStatBase($statisticsType, $sourceType)
                          ->toArray();
        } elseif ($orderType == OrderMerchantEnum::ORDER_TYPE_TOTAL) {
            $calc = array_merge($order->inOrderStatBase($statisticsType)
                                      ->toArray(),
                $order->waiMaiOrderStatBase($statisticsType, $sourceType)
                      ->toArray());
        } else {
            throw new OrderException(OrderCodeEnum::ERR_ORDER_IN_OUT_TYPE);
        }

        if ($vipIn) {
            $calc = array_merge($calc, $order->couponPackageOrderStatBase($statisticsType)
                                             ->toArray());
        }

        // 循环所有明细数据，并放到对应的时间段内
        for ($i = $startTime; $i < $endTime; $i += $interval) {
            $num  = 0;
            $incr = 0;

            foreach ($calc as $v) {

                // 符合的情况
                if ($v['time'] >= $i && $v['time'] < $i + $interval) {
                    $num += (int)$v['num'];
                    $incr++;
                }
            }

            // 『单均』特殊处理
            if (in_array($statisticsType, [
                OrderMerchantEnum::STAT_BEFORE_DISCOUNT_AVG_PRICE,
                OrderMerchantEnum::STAT_AFTER_DISCOUNT_AVG_PRICE,
                OrderMerchantEnum::STAT_INCOME_RATE,
            ])) {
                $num = $incr > 0 ? floor($num / $incr) : 0;
            }

            if ($statisticsType == OrderMerchantEnum::STAT_INCOME_RATE) {
                $num = (float)bcdiv($num, 100, 2);
            }

            switch ($showTimeTab) {
                case OrderMerchantEnum::SHOW_TIME_TAB_TODAY:
                case OrderMerchantEnum::SHOW_TIME_TAB_YESTERDAY:
                    $time = sprintf("%02s", date('H', $i)) . ':00';
                    break;
                case OrderMerchantEnum::SHOW_TIME_TAB_WEEK:
                    $w    = date('w', $i);
                    $time = CommonService::wToWord($w);
                    break;
                case OrderMerchantEnum::SHOW_TIME_TAB_DEFINE:
                    if ($interval == 3600) {
                        $time = sprintf("%02s", date('H', $i)) . ':00';
                    } else {
                        $time = date('m/d', $i);
                    }
                    break;

                default:
                    $time = date('m/d', $i);
                    break;
            }

            $charts[] = [
                'time' => $time,
                'num'  => $num,
            ];
        }

        Cache::put($cacheKey, $charts, OrderCacheEnum::ORDER_MERCHANT_CHARTS_TTL);

        return $charts;
    }

    /**
     * 会员收入统计 - 列表
     * @param array $couponPackageIds
     * @param int $phone
     * @param int $lastUnionId
     * @param int $limit
     * @return mixed
     */
    protected function couponPackageListsBase(array $couponPackageIds, int $phone, int $lastUnionId, int $limit)
    {
        return CouponPackageOrderModel::query()
                                      ->where('shopId', $this->shopIds[0])
                                      ->where('payStatus', CouponPackageEnum::PAY_STATUS_ON)
                                      ->whereBetween('createdAt', [$this->startTime, $this->endTime])
                                      ->with(['customerRel', 'couponPackageRel'])
                                      ->when(count($couponPackageIds), function ($query) use ($couponPackageIds) {
                                          $query->whereIn('couponPackageId', $couponPackageIds);
                                      })
                                      ->when($phone, function ($query) use ($phone) {
                                          $userIds = CustomerModel::query()
                                                                  ->where('mobile', $phone)
                                                                  ->pluck('id');
                                          $query->whereIn('userId', $userIds);
                                      })
                                      ->when($lastUnionId, function ($query) use ($lastUnionId) {
                                          $query->where('orderId', '<', $lastUnionId);
                                      })
                                      ->orderByDesc('orderId')
                                      ->limit($limit)
                                      ->get()
                                      ->map(function ($item) {
                                          return [
                                              'id'                => $item->orderId,
                                              'couponPackageId'   => (int)optional($item->couponPackageRel)->id,
                                              'couponPackageName' => (string)optional($item->couponPackageRel)->name,
                                              'salesTime'         => $item->createdAt->toDateTimeString(),
                                              'turnover'          => (int)optional($item->couponPackageRel)->salePrice,
                                              'income'            => $item->payPrice,
                                              'phone'             => (string)optional($item->customerRel)->hiddenMobile,
                                          ];
                                      });
    }

    /**
     * 支付明细统计 - 列表
     * @param int $payType
     * @param int $payStatus
     * @param int $lastUnionId
     * @param int $limit
     * @param bool $isNew
     * @return mixed
     */
    protected function payUnionListsBase(
        int $payType,
        int $payStatus,
        int $lastUnionId,
        int $limit,
        bool $isNew = false
    ) {

        $engine = (new SeparateService($this->startTime, $this->endTime))->check();
        if ($engine == SeparateService::DB) {
            (new BaseModel())->setSplitShopId($this->shopIds[0]);
            $model = OrderPayUnionSplitModel::suffix($this->shopIds[0]);
        } else {
            $model = OrderPayUnionCHModel::query();
        }

        return $model
                                      ->with(['customPaymentsRel', 'payStreamsRel', 'refundStreamsRel'])
                                      ->where('shopId', $this->shopIds[0])
                                      ->whereBetween('createdAt', [$this->startTime, $this->endTime])
                                      ->where('payType', '>', 0)
                                      ->when($payStatus, function ($query) use ($payStatus) {
                                          $query->where('payStatus', $payStatus);
                                      })
                                      ->when($payType, function ($query) use ($isNew, $payType) {
                                          if ($payType >= OrderPayUnionSplitModel::PAY_TYPE_DEFINE) {
                                              $query->where('payType', '>=', $payType);
                                          } else {
                                              if ($isNew && in_array($payType,
                                                      array_keys(OrderPayUnionSplitModel::WAIMAI_PAY_TYPE_MAP))) {
                                                  $query->where('childType',
                                                      OrderPayUnionSplitModel::WAIMAI_PAY_TYPE_MAP[$payType] ?? 0);
                                                  $query->where('payType',
                                                      OrderPayUnionSplitModel::PAY_TYPE_TAKEOUT);// 外卖类型
                                              } else {
                                                  $query->where('payType', $payType);
                                              }
                                          }
                                      })
                                      ->when($lastUnionId, function ($query) use ($lastUnionId) {
                                          $query->where('id', '<', $lastUnionId);
                                      })
                                      ->orderByDesc('id')
                                      ->limit($limit)
                                      ->get()
                                      ->map(function ($item) {
                                          $payType     = $item->payType;
                                          $payTypeText = $item->payTypeText;
                                          if ($item->payType == OrderPayUnionSplitModel::PAY_TYPE_TAKEOUT) {// 外卖类型
                                              switch ($item->childType) {
                                                  case CodeEnum::SOURCE_TYPE_MT:
                                                      $payType = OrderPayUnionSplitModel::PAY_TYPE_MT_WAIMAI;
                                                      break;
                                                  case CodeEnum::SOURCE_TYPE_ELM:
                                                      $payType = OrderPayUnionSplitModel::PAY_TYPE_ELE_WAIMAI;
                                                      break;
                                                  case  CodeEnum::SOURCE_TYPE_DY:
                                                      $payType = OrderPayUnionSplitModel::PAY_TYPE_DY_WAIMAI;
                                                      break;
                                              }
                                              $payTypeText = OrderPayUnionSplitModel::PAY_TYPE_TEXT_NEW[$payType] ?? 0;
                                          }
                                          return [
                                              'unionId'       => (string)$item->id,
                                              'bizId'         => (string)$item->bizId,
                                              'payType'       => $payType,
                                              'payTypeText'   => $payTypeText,
                                              'payPrice'      => $item->payPrice,
                                              'originalPrice' => $item->originalPrice,
                                              'payStatus'     => $item->payStatus,
                                              'payStatusText' => $item->payStatusText,
                                              'createdAt'     => $item->createdAt,
                                              'orderId'       => $item->orderId,
                                              'childType'     => $item->childType,
                                              'childTypeDesc' => $item->childTypeDesc,
                                          ];
                                      });
    }

    /**
     * 支付明细统计，聚合统计数据
     *
     * @param int $payType
     * @param int $payStatus
     * @return array
     */
    protected function payUnionListsStatisticsBase(int $payType, int $payStatus): array
    {
        $obj = OrderPayUnionSplitModel::suffix($this->shopIds[0])
                                      ->where('shopId', $this->shopIds[0])
                                      ->whereBetween('createdAt', [$this->startTime, $this->endTime])
                                      ->where('payType', '>', 0)
                                      ->where('payPrice', '>', 0)
                                      ->when($payStatus, function ($query) use ($payStatus) {
                                          $query->where('payStatus', $payStatus);
                                      })
                                      ->when($payType, function ($query) use ($payType) {
                                          if ($payType >= OrderPayUnionSplitModel::PAY_TYPE_DEFINE) {
                                              $query->where('payType', '>=', $payType);
                                          } else {
                                              $query->where('payType', $payType);
                                          }
                                      });

        $res = $obj->select(DB::raw("sum(payPrice) as sumPayPrice"), DB::raw("count(*) as countPay"))
                   ->get();

        if ($payStatus == OrderPayUnionSplitModel::PAY_STATUS_OK) {
            return [
                'sumPayPrice'    => (int)$res[0]->sumPayPrice,
                'countPay'       => (int)$res[0]->countPay,
                'sumRefundPrice' => 0,
                'countRefund'    => 0,
            ];
        } elseif ($payStatus == OrderPayUnionSplitModel::PAY_STATUS_REFUND) {
            return [
                'sumPayPrice'    => 0,
                'countPay'       => 0,
                'sumRefundPrice' => (int)$res[0]->sumPayPrice,
                'countRefund'    => (int)$res[0]->countPay,
            ];
        } else {
            $payObj = clone $obj;
            $payRes = $payObj->where('payStatus', OrderPayUnionSplitModel::PAY_STATUS_OK)
                             ->select(DB::raw("sum(payPrice) as sumPayPrice"), DB::raw("count(*) as countPay"))
                             ->get();

            $refundObj = clone $obj;
            $refundRes = $refundObj->where('payStatus', OrderPayUnionSplitModel::PAY_STATUS_REFUND)
                                   ->select(DB::raw("sum(payPrice) as sumPayPrice"), DB::raw("count(*) as countPay"))
                                   ->get();

            return [
                'sumPayPrice'    => (int)$payRes[0]->sumPayPrice,
                'countPay'       => (int)$payRes[0]->countPay,
                'sumRefundPrice' => (int)$refundRes[0]->sumPayPrice,
                'countRefund'    => (int)$refundRes[0]->countPay,
            ];
        }
    }


    /**
     * 会员收入统计，聚合统计数据
     *
     * @param array $couponPackageIds
     * @param int $phone
     * @return array
     */
    public function couponPackageListsStatisticsBase(array $couponPackageIds, int $phone)
    {
        $lists    = CouponPackageOrderModel::query()
                                           ->where('shopId', $this->shopIds[0])
                                           ->where('payStatus', CouponPackageEnum::PAY_STATUS_ON)
                                           ->with(['customerRel', 'couponPackageRel'])
                                           ->when(count($couponPackageIds), function ($query) use ($couponPackageIds) {
                                               $query->whereIn('couponPackageId', $couponPackageIds);
                                           })
                                           ->when($phone, function ($query) use ($phone) {
                                               $userIds = CustomerModel::query()
                                                                       ->where('mobile', $phone)
                                                                       ->pluck('id');
                                               $query->whereIn('userId', $userIds);
                                           })
                                           ->whereBetween('createdAt',
                                               [$this->startTime, $this->endTime])
                                           ->get();
        $turnover = 0; //营业额
        $income   = 0; //营业收入
        $count    = 0; //有效订单
        if ($lists->count()) {
            foreach ($lists as $list) {
                $turnover += (int)optional($list->couponPackageRel)->salePrice;
                $income   += $list->payPrice;
                ++$count;
            }
        }
        return [
            'turnover' => $turnover,
            'income'   => $income,
            'count'    => $count
        ];
    }

    /**
     * 支付明细统计，支付详情
     * @param int $unionId
     * @return array[]
     * @throws PayException
     */
    protected function payUnionDetailBase(int $unionId)
    {
        $union = OrderPayUnionSplitModel::suffix($this->shopIds[0])
                                        ->find($unionId);
        if (!$union) {
            $union = OrderPayUnionCHModel::query()->find($unionId);
        }

        if (!$union) {
            throw new PayException(PayCodeEnum::ERR_PAY_UNION_ID);
        }

        $shop = ShopService::getShopInfo($this->shopIds[0]);
        if (!$shop) {
            throw new ShopException(ShopCodeEnum::ERR_SHOP_ID_NO_EXIST);
        }

        $payPrice      = $union->payPrice;
        $discountPrice = 0;
        $payStatusText = $union->payStatusText;
        $createAt      = date('Y-m-d H:i:s', $union->createdAt);
        $orderId       = $union->orderId;
        $bizId         = $union->bizId;
        $payTypeText   = OrderPayUnionSplitModel::PAY_TYPE_TEXT[$union->payType] ?? '';
        $code          = $shop->kfShopCode;
        $name          = $shop->name;

        switch ($union->payType) {
            case OrderPayUnionSplitModel::PAY_TYPE_FY:
                $discountPrice   = 0;
                $payChannelChild = 0;

                if ($union->payStatus == OrderPayUnionSplitModel::PAY_STATUS_OK) {
                    $pay             = PayStreamModel::getDataByPayNo($union->bizId);
                    $payChannelChild = $pay->payChannelChild ?? 0;
                } elseif ($union->payStatus == OrderPayUnionSplitModel::PAY_STATUS_REFUND) {
                    $pay             = RefundStreamModel::query()
                                                        ->find($union->bizId);
                    $payChannelChild = $pay->refundChannelChild ?? 0;
                }

                $payTypeText = "富友 - " . (PayStreamModel::PAY_CHANNEL_CHILD_TEXT[$payChannelChild] ?? '');
                break;
            case OrderPayUnionSplitModel::PAY_TYPE_CASH:
                $discountPrice = 0;
                break;
            case OrderPayUnionSplitModel::PAY_TYPE_COUPON_KF:
                $coupon        = OrderCouponSplitModel::suffix($this->shopIds[0])
                                                      ->find($union->bizId);
                $payPrice      = $union->payPrice;
                $discountPrice = ($coupon->couponDiscountPrice ?? 0) - ($coupon->couponCostPrice ?? 0);
                break;
            case OrderPayUnionSplitModel::PAY_TYPE_MT_GROUP_BUY:
            case OrderPayUnionSplitModel::PAY_TYPE_DY_GROUP_BUY:
                $couponExt     = OrderCouponExtSplitModel::suffix($this->shopIds[0])
                                                         ->find($union->bizId);
                $payPrice      = $union->payPrice;
                $discountPrice = ($couponExt->couponExtDiscountPrice ?? 0) - ($couponExt->couponExtCostPrice ?? 0);
                break;
        }

        return [
            'pay'   => [
                'payPrice'      => $payPrice,
                'discountPrice' => $discountPrice,
                'payTypeText'   => $payTypeText,
                'payTypeDetail' => $union->childTypeDesc,
                'originalPrice' => $union->originalPrice,
                'payStatusText' => $payStatusText,
            ],
            'order' => [
                'createdAt' => $createAt,
                'orderId'   => (string)$orderId,
                'bizId'     => (string)$bizId,
            ],
            'shop'  => [
                'code' => $code,
                'name' => $name,
            ],
        ];
    }

    /**
     * 会员收入统计，支付详情
     * @param int $orderId
     * @return array[]
     * @throws CouponPackageException
     */
    protected function couponPackageDetailBase(int $orderId): array
    {
        $list = CouponPackageOrderModel::query()
                                       ->where('shopId', $this->shopIds[0])
                                       ->where('payStatus', CouponPackageEnum::PAY_STATUS_ON)
                                       ->where('orderId', $orderId)
                                       ->with(['customerRel', 'shopRel', 'couponPackageRel'])
                                       ->first();
        if (!$list) {
            throw new CouponPackageException(CouponPackageCodeEnum::ERR_COUPON_PACKAGE_NOT_NULL);
        }

        $extOrderId = OrderExternalSplitModel::suffix($this->shopIds[0])
                                             ->query()
                                             ->where('extOrderId', $list->orderId)
                                             ->value('orderId');
        $payNo      = PayStreamModel::suffix($this->shopIds[0], PayStreamModel::SYS_TYPE_RMS_MEAL)
                                    ->where('shopId', $this->shopIds[0])
                                    ->where('orderId', $extOrderId)
                                    ->value('payNo');

        return [
            'couponPackageCode' => $list->couponPackageId,
            'couponPackageName' => (string)optional($list->couponPackageRel)->name,
            'phone'             => (string)optional($list->customerRel)->hiddenMobile,
            'shopCode'          => (int)optional($list->shopRel)->shopCode,
            'shopName'          => (string)optional($list->shopRel)->name,
            'turnover'          => (int)optional($list->couponPackageRel)->salePrice,
            'income'            => $list->payPrice,
            'salesTime'         => $list->createdAt->toDateTimeString(),
            'payNo'             => $payNo ?: '',
        ];
    }

    /**
     * 店铺是否关联券包
     * @return int
     */
    protected function checkCouponPackage(): int
    {
        return Cache::remember(OrderCacheEnum::getShopBindCouponPackage($this->shopIds[0]), 600, function () {
            return (int)(bool)(
                CouponPackageShopMappingModel::query()
                                             ->where('shopId', $this->shopIds[0])
                                             ->selectRaw(1)
                                             ->first()
                ||
                CouponPackageOrderModel::query()
                                       ->where('shopId', $this->shopIds[0])
                                       ->selectRaw(1)
                                       ->first());
        });
    }

    /**
     * 堂食菜品销售列表
     *
     * 单个菜+套餐，套餐下的菜不统计
     * @param array $filterIds
     * @param int $groupByType
     * @return mixed
     */
    protected function inOrderProductStatisticsBase(array $filterIds, int $groupByType)
    {
        $timeColumn = OrderMerchantEnum::ORDER_TYPE_TIME_COLUMN[OrderMerchantEnum::ORDER_TYPE_IN];

        // 隔断查询
        $engine = (new SeparateService($this->startTime, $this->endTime))->check();
        if ($engine == SeparateService::DB) {
            $orderTable             = OrderSplitModel::suffix($this->shopIds[0])->getTable();
            $orderDetailTable       = OrderDetailSplitModel::suffix($this->shopIds[0])->getTable();
            $orderDetailTablePrefix = config('other.DB_PREFIX', '') . $orderDetailTable;
            $query                  = OrderDetailSplitModel::query()
                                                           ->join($orderTable, $orderDetailTable . '.orderId', '=',
                                                               $orderTable . '.orderId');
        } else {
            $orderTable             = (new OrderCHModel)->getTable();
            $orderDetailTable       = (new OrderDetailCHModel)->getTable();
            $orderDetailTablePrefix = $orderDetailTable;

            $query = OrderDetailCHModel::query()->join($orderTable, 'all', 'inner', ['orderId', 'orderId']);
        }

        $query = $query
            ->where($orderTable . '.orderStatus', CodeEnum::ORDER_STATUS_FINISHED)
            ->where($orderTable . '.shopId', $this->shopIds[0])
            ->where($orderDetailTable . '.shopId', $this->shopIds[0])
            ->whereBetween($orderTable . '.' . $timeColumn,
                [$this->startTime, $this->endTime])
            ->where($orderDetailTable . '.type', 0);


        if ($groupByType == OrderMerchantEnum::PRODUCT_SALES_GROUP_BY_PRODUCT) {
            $data = $query->when($filterIds, function ($query) use ($filterIds, $orderDetailTable) {
                return $query->whereIn($orderDetailTable . '.productId', $filterIds);
            })
                         ->where($orderDetailTable . '.num', '>', 0)
                         ->where($orderDetailTable . '.refundNum', 0)
                         ->groupBy($orderDetailTable . '.productId')
                         ->when($engine == SeparateService::DB, function ($query) use ($orderDetailTablePrefix) {
                             $query->selectRaw("{$orderDetailTablePrefix}.productId as id, {$orderDetailTablePrefix}.productName as name, sum({$orderDetailTablePrefix}.num) as salesNum, sum({$orderDetailTablePrefix}.payPrice+{$orderDetailTablePrefix}.couponCostPrice) as incomes");
                         })
                         ->when($engine == SeparateService::CLICKHOUSE,
                             function ($query) use ($orderDetailTablePrefix) {
                                 $query->select(raw("productId as id"),
//                                     raw("productName as name"),
                                     raw("sum({$orderDetailTablePrefix}.num) as salesNum"),
                                     raw("sum({$orderDetailTablePrefix}.payPrice+{$orderDetailTablePrefix}.couponCostPrice) as incomes"));
                             })
                         ->get();

            // db 不处理直接返回
            if ($engine == SeparateService::DB) {
                return $data;
            }

            // clickhouse需要处理productName
            $productIds = $data->pluck('id');
            $products   = Product::query()
                                      ->whereIn('id', $productIds)
                                      ->select('id', 'name')
                                      ->get()
                                      ->keyBy('id');

            return $data->map(function ($item) use ($products) {
                $item['name'] = $products[$item['id']]['name'] ?? '';
                return $item;
            });
        }

        if ($groupByType == OrderMerchantEnum::PRODUCT_SALES_GROUP_BY_CATEGORY) {
            $data = $query->when($filterIds, function ($query) use ($filterIds, $orderDetailTable) {
                return $query->whereIn($orderDetailTable . '.categoryId', $filterIds);
            })
//                         ->with('categoryRel')
                          ->groupBy($orderDetailTable . '.categoryId')
                          ->when($engine == SeparateService::DB, function ($query) use ($orderDetailTablePrefix) {
                              $query->selectRaw("{$orderDetailTablePrefix}.categoryId, sum({$orderDetailTablePrefix}.num) as salesNum, sum({$orderDetailTablePrefix}.payPrice+{$orderDetailTablePrefix}.couponCostPrice) as incomes");
                          })
                          ->when($engine == SeparateService::CLICKHOUSE,
                              function ($query) use ($orderDetailTablePrefix) {
                                  $query->select(raw("{$orderDetailTablePrefix}.categoryId"),
                                      raw("sum({$orderDetailTablePrefix}.num) as salesNum"),
                                      raw("sum({$orderDetailTablePrefix}.payPrice+{$orderDetailTablePrefix}.couponCostPrice) as incomes"));
                              })
                          ->get()
                          ->map(function ($item) {
                              return [
                                  'id'       => (int)$item['categoryId'],
//                                 'name'     => optional($item->categoryRel)->name,
                                  'salesNum' => $item->salesNum,
                                  'incomes'  => $item->incomes,
                              ];
                          });

            // 处理categoryName
            $categoryIds = $data->pluck('id');
            $categorys   = CategoryModel::query()
                                        ->whereIn('id', $categoryIds)
                                        ->select('id', 'name')
                                        ->get()
                                        ->keyBy('id');

            return $data->map(function ($item) use ($categorys) {
                $item['name'] = $categorys[$item['id']]['name'] ?? '';
                return $item;
            });
        }

        throw new ProductException(ProductCodeEnum::ERR_PRODUCT_SALES_GROUP_BY_TYPE);
    }

    /**
     * 外卖菜品销售列表
     *
     * 单个菜
     * @param array $filterNames
     * @param int $groupByType
     * @return mixed
     */
    protected function waiMaiOrderProductStatisticsBase(array $filterNames, int $groupByType, int $sourceType)
    {
        $timeColumn = OrderMerchantEnum::ORDER_TYPE_TIME_COLUMN[OrderMerchantEnum::ORDER_TYPE_WAI_MAI];

        // 隔断查询
        $engine = (new SeparateService($this->startTime, $this->endTime))->check();
        if ($engine == SeparateService::DB) {
            $prefix           = config('other.DB_PREFIX', '');
            $orderTable       = WaiMaiOrderModel::suffix($this->shopIds[0])->getTable();
            $orderTablePrefix = $prefix . $orderTable;
            $orderDetailTable = WaiMaiOrderDetailModel::suffix($this->shopIds[0])->getTable();
            $query            = WaiMaiOrderModel::suffix($this->shopIds[0])
                                                ->join($orderDetailTable, "{$orderTable}.orderId", '=',
                                                    "{$orderDetailTable}.orderId");
        } else {
            $orderTable = (new WaiMaiOrderCHModel())->getTable();
            $orderTablePrefix = '';
            $orderDetailTable = (new WaiMaiOrderDetailCHModel())->getTable();

            $query = WaiMaiOrderDetailCHModel::query()->join($orderTable, 'all', 'inner', ['orderId', 'orderId']);
        }

        $query = $query
            ->where("{$orderTable}.shopId", $this->shopIds[0])
            ->where('orderStatus', '!=', WaiMaiDBEnum::ORDER_STATUS_7)
            ->whereBetween($orderTable . '.' . $timeColumn, [$this->startTime, $this->endTime])
            ->when($sourceType, function ($query) use ($sourceType, $orderTable) {
                $query->where("{$orderTable}.sourceType", $sourceType);
            });

        if ($groupByType == OrderMerchantEnum::PRODUCT_SALES_GROUP_BY_PRODUCT) {
            return $query->when($filterNames, function ($query) use ($filterNames) {
                return $query->whereIn('productNameStandard', $filterNames);
            })
                         ->groupBy('productNameStandard', "{$orderDetailTable}.sourceType")
                         ->when($engine == SeparateService::DB, function ($query) use ($orderTablePrefix) {
                             $query->selectRaw("{$orderTablePrefix}.orderId as orderId, productNameStandard as name, sum(num) as salesNum, sum(incomes) as incomes, {$orderTablePrefix}.sourceType as sourceType");
                         })
                         ->when($engine == SeparateService::CLICKHOUSE, function ($query) use ($orderDetailTable) {
                             $query->select(raw("productNameStandard as name"), raw("sum(num) as salesNum"),
                                 raw("sum(incomes) as incomes"), raw("{$orderDetailTable}.sourceType as sourceType"));
                         })
                         ->get();
        }

        throw new ProductException(ProductCodeEnum::ERR_PRODUCT_SALES_GROUP_BY_TYPE);
    }

    /**
     * 格式化百分比
     * @param numeric $changeNum 变量
     * @param numeric $oriNum 原量
     * @return float
     */
    public static function formatPercent($changeNum, $oriNum): float
    {
        if ($changeNum == 0) {
            return 0;
        }

        if ($oriNum == 0) {
            return 100;
        }

        return (float)bcmul(bcdiv($changeNum, $oriNum, 4), 100, 2);
    }

    public function getCouponPackageNameByOrder(int $shopId)
    {
        $couponPackageIds = Cache::remember(OrderCacheEnum::getCouponPackageNameByOrder($shopId),
            OrderCacheEnum::COUPON_PACKAGE_NAME_BY_ORDER_TTL, function () use ($shopId) {
                return CouponPackageOrderModel::query()
                                              ->where('shopId', $shopId)
                                              ->where('payStatus', CouponPackageOrderModel::PAY_STATUS_1)
                                              ->groupBy('couponPackageId')
                                              ->pluck('couponPackageId');
            });
        if (!$couponPackageIds->count()) {
            return collect();
        }
        return CouponPackageModel::query()
                                 ->whereIn('id', $couponPackageIds)
                                 ->orderByDesc('id')
                                 ->pluck('name', 'id');
    }


    /**
     * 支付方式 - 聚合统计
     *
     * @return array
     */
    public function groupStatisticsBase()
    {
        $count = 0;
        $sum   = 0;

        $data = OrderPayUnionSplitModel::suffix($this->shopIds[0])
                                       ->where('shopId', $this->shopIds[0])
                                       ->where('payType', '>', 0)
                                       ->where('payPrice', '>', 0)
                                       ->whereBetween('createdAt', [$this->startTime, $this->endTime])
                                       ->get();

        $removeOrderIds = $data->groupBy("orderId")->map(function ($v, $k) {
            $actuallyPayAmount = $v->where("payStatus", OrderPayUnionSplitModel::PAY_STATUS_OK)->sum("payPrice") -
                $v->where("payStatus", OrderPayUnionSplitModel::PAY_STATUS_REFUND)->sum("payPrice");
            if ($actuallyPayAmount <= 0) {
                return $k;
            }
        })->filter()->values()->toArray();


        $queryResult = $data->whereNotIn("orderId", $removeOrderIds)
                            ->each(function (&$v) {
                                $v->payType   = $v->payType > 100 ? 100 : $v->payType;
                                $v->payPrice  = $v->payStatus == OrderPayUnionSplitModel::PAY_STATUS_REFUND ? "-" . $v->payPrice : $v->payPrice;
                                $v->childType = $v->payType == OrderPayUnionSplitModel::PAY_TYPE_DY_GROUP_BUY ? md5($v->childTypeDesc) : $v->childType;
                            })
                            ->groupBy("payType")
                            ->map(function (Collection $parent, $payType) use (&$count, &$sum) {
                                $sumPrice   = $parent->sum("payPrice");
                                $countTotal = $parent->where("payStatus", OrderPayUnionSplitModel::PAY_STATUS_OK)
                                                     ->count();
                                $count      += $countTotal;
                                $sum        += $sumPrice;
                                return [
                                    "type"        => $payType,
                                    "count"       => $countTotal,
                                    "sum"         => $sumPrice,
                                    "description" => OrderPayUnionSplitModel::PAY_TYPE_TEXT[$payType],
                                    "child"       => $payType == OrderPayUnionSplitModel::PAY_TYPE_CASH ?
                                        [] : $parent
                                            ->groupBy("childType")
                                            ->map(function (Collection $child, $chidType) {
                                                return [
                                                    "childType"   => (int)$chidType,
                                                    "description" => $child->getIterator()->current()
                                                        ->childTypeDesc,
                                                    "count"       => $child
                                                        ->where("payStatus", OrderPayUnionSplitModel::PAY_STATUS_OK)
                                                        ->count(),
                                                    "sum"         => $child->sum("payPrice")
                                                ];
                                            })->values()
                                ];
                            })->prepend([
                "type"        => 0,
                "count"       => $count,
                "sum"         => $sum,
                "description" => "营业收入",
                "child"       => []
            ])->values();

        unset($data);

        return collect(OrderPayUnionSplitModel::PAY_TYPE_TEXT)->map(function ($v, $k) use ($queryResult) {
            if ($typeRes = $queryResult->where("type", $k)->first()) {
                return $typeRes;
            }
            return [
                "type"        => $k,
                "count"       => 0,
                "sum"         => 0,
                "description" => $k == OrderPayUnionSplitModel::PAY_TYPE_FY ? "扫码收款（含手续费0.3%）" : OrderPayUnionSplitModel::PAY_TYPE_TEXT[$k],
                "child"       => []
            ];
        })->prepend($queryResult->where("type", 0)->first())->values()->toArray();
    }


    /**
     * 支付方式 - 聚合统计
     *
     * @return array
     */
    public function groupStatisticsBaseNew(): array
    {
        $engine = (new SeparateService($this->startTime, $this->endTime))->check();
        if ($engine == SeparateService::DB) {
            $model = OrderPayUnionSplitModel::suffix($this->shopIds[0]);
        } else {
            $model = new OrderPayUnionCHModel;
        }

        $data = $model
            ->where('shopId', $this->shopIds[0])
            ->whereBetween('createdAt', [$this->startTime, $this->endTime])
            ->where('payType', '>', 0)
            ->where('payPrice', '>', 0)
            ->get();

        $removeOrderIds = $data->groupBy("orderId")->map(function ($v, $k) {
            $actuallyPayAmount = $v->where("payStatus", OrderPayUnionSplitModel::PAY_STATUS_OK)->sum("payPrice") -
                $v->where("payStatus", OrderPayUnionSplitModel::PAY_STATUS_REFUND)->sum("payPrice");
            if ($actuallyPayAmount <= 0) {
                return $k;
            }
        })->filter()->values()->toArray();

        $queryResult = $data->whereNotIn("orderId", $removeOrderIds)
                            ->each(function (&$v) {
                                $v->payType   = $v->payType > 100 ? 100 : $v->payType;
                                $v->payPrice  = $v->payStatus == OrderPayUnionSplitModel::PAY_STATUS_REFUND ? "-" . $v->payPrice : $v->payPrice;
                                $v->childType = $v->payType == OrderPayUnionSplitModel::PAY_TYPE_DY_GROUP_BUY ? md5($v->childTypeDesc) : $v->childType;

                                // 外卖区分
                                if ($v->payType == OrderPayUnionSplitModel::PAY_TYPE_TAKEOUT) {
                                    switch ($v->childType) {
                                        case  CodeEnum::SOURCE_TYPE_MT:
                                            $v->payType = OrderPayUnionSplitModel::PAY_TYPE_MT_WAIMAI;
                                            break;
                                        case  CodeEnum::SOURCE_TYPE_ELM:
                                            $v->payType = OrderPayUnionSplitModel::PAY_TYPE_ELE_WAIMAI;
                                            break;
                                        case  CodeEnum::SOURCE_TYPE_DY:
                                            $v->payType = OrderPayUnionSplitModel::PAY_TYPE_DY_WAIMAI;
                                            break;
                                    }
                                }
                            })
                            ->groupBy("payType")
                            ->map(function (Collection $parent, $payType) {
                                $sumPrice   = $parent->sum("payPrice");
                                $countTotal = $parent->where("payStatus", OrderPayUnionSplitModel::PAY_STATUS_OK)
                                                     ->count();
                                // 退款
                                $sumRefundPrice   = abs($parent->where("payStatus",
                                    OrderPayUnionSplitModel::PAY_STATUS_REFUND)
                                                               ->sum("payPrice"));
                                $countRefundTotal = $parent->where("payStatus",
                                    OrderPayUnionSplitModel::PAY_STATUS_REFUND)
                                                           ->count();


                                return [
                                    "type"        => $payType,
                                    "count"       => $countTotal,
                                    "sum"         => bcdiv100($sumPrice),
                                    "countRefund" => $countRefundTotal,
                                    "sumRefund"   => bcdiv100(abs($sumRefundPrice)),
                                    "description" => OrderPayUnionSplitModel::PAY_TYPE_TEXT_NEW[$payType] ?? "",
                                ];
                            })->keyBy('type')->toArray();

        unset($data);

        $total = [
            "count"       => 0,
            "sum"         => 0,
            "countRefund" => 0,
            "sumRefund"   => 0,
        ];

        $model  = 1;
        $config = [];
        collect(ConfigService::getPayUnionConfig())->where('type', $model)->map(function ($item) use (&$config) {
            $config = $item;
        });

        $data = collect(OrderPayUnionSplitModel::PAY_TYPE_TEXT_NEW)->map(function ($v, $k) use (
            $model,
            $config,
            &$total,
            $queryResult
        ) {
            $count = $queryResult[$k]['count'] ?? 0;
            $sum   = $queryResult[$k]['sum'] ?? 0;
            if ($count > 0 || $sum > 0) {// 有效订单和总实收 存在则返回
                $countRefund = $queryResult[$k]['countRefund'] ?? 0;
                $sumRefund   = $queryResult[$k]['sumRefund'] ?? 0;

                $total['count']       += $count;
                $total['sum']         += $sum;
                $total['countRefund'] += $countRefund;
                $total['sumRefund']   += $sumRefund;

                return [
                    "type"             => $k,
                    "typeText"         => $v,
                    "count"            => $count,
                    "sum"              => $sum,
                    "countRefund"      => $countRefund,
                    "sumRefund"        => $sumRefund,
                    'model'            => $model,
                    'modelText'        => $config['name'] ?? '',// 合同模式 1-传统 2-分账
                    "platformRate"     => $config['data'][$k]['platformRate'] ?? '',// 平台费率
                    "settlementCycle"  => $config['data'][$k]['settlementCycle'] ?? '',// 打款周期
                    "platformRateDesc" => $config['data'][$k]['platformRateDesc'] ?? '',// 平台费率说明
                    "jumpUrl"          => $config['data'][$k]['jumpUrl'] ?? '',// 跳转URL-Android
                    "jumpUrlIos"       => $config['data'][$k]['jumpUrlIos'] ?? '',// 跳转URL-IOS
                    "jumpUrlDesc"      => $config['data'][$k]['jumpUrlDesc'] ?? '',// 跳转URL ？说明
                    "jumpUrlText"      => $config['data'][$k]['jumpUrlText'] ?? '',// 跳转URL按钮文本
                    "jumpUrlType"      => $config['data'][$k]['jumpUrlType'] ?? '',// 跳转URL类型 1-对内。2-对外
                ];
            }
        })->filter()->values()->toArray();

        $total['sum']       = bcdiv100($total['sum'] * 100);
        $total['sumRefund'] = bcdiv100($total['sumRefund'] * 100);
        return ['data' => $data, 'total' => $total];
    }

    /**
     * 支付明细统计，聚合统计数据
     *
     * @param int $payType
     * @param int $payStatus
     * @return array
     */
    protected function payUnionListsStatisticsBaseNew(int $payType, int $payStatus): array
    {
        $engine = (new SeparateService($this->startTime, $this->endTime))->check();
        if ($engine == SeparateService::DB) {
            $model = OrderPayUnionSplitModel::suffix($this->shopIds[0]);
        } else {
            $model = OrderPayUnionCHModel::query();
        }

        $obj = $model
            ->where('shopId', $this->shopIds[0])
            ->whereBetween('createdAt', [$this->startTime, $this->endTime])
            ->where('payType', '>', 0)
            ->where('payPrice', '>', 0)
            ->when($payStatus, function ($query) use ($payStatus) {
                $query->where('payStatus', $payStatus);
            })
            ->when($payType, function ($query) use ($payType) {
                if ($payType >= OrderPayUnionSplitModel::PAY_TYPE_DEFINE) {
                    $query->where('payType', '>=', $payType);
                } else {
                    if (in_array($payType,
                        array_keys(OrderPayUnionSplitModel::WAIMAI_PAY_TYPE_MAP))) {
                        $query->where('childType',
                            OrderPayUnionSplitModel::WAIMAI_PAY_TYPE_MAP[$payType] ?? 0);
                        $query->where('payType',
                            OrderPayUnionSplitModel::PAY_TYPE_TAKEOUT);// 外卖类型
                    } else {
                        $query->where('payType', $payType);
                    }
                }
            });

        $removeOrderIdsObj = clone $obj;
        $removeOrderIds    = $removeOrderIdsObj->get()->groupBy("orderId")->map(function ($v, $k) {
            $actuallyPayAmount = $v->where("payStatus", OrderPayUnionSplitModel::PAY_STATUS_OK)->sum("payPrice") -
                $v->where("payStatus", OrderPayUnionSplitModel::PAY_STATUS_REFUND)->sum("payPrice");
            if ($actuallyPayAmount <= 0) {
                return $k;
            }
        })->filter()->values()->toArray();

        $listObjRefund = clone $obj;

        $listRefund = $listObjRefund->whereNotIn("orderId", $removeOrderIds)
                                    ->where('payStatus', OrderPayUnionSplitModel::PAY_STATUS_REFUND)
                                    ->groupBy('childTypeDesc')
                                    ->when($engine == SeparateService::DB, function ($query) {
                                        $query->select(DB::raw("sum(payPrice) as sumPayPrice"), 'childTypeDesc', 'payType');
                                    })
                                    ->when($engine == SeparateService::CLICKHOUSE, function ($query) {
                                        $query->select(raw("sum(payPrice) as sumPayPrice"), "childTypeDesc");
                                    })
                                    ->get()
                                    ->keyBy('childTypeDesc');

        $listObj = clone $obj;
        $list    = $listObj->whereNotIn("orderId", $removeOrderIds)
                           ->where('payStatus', OrderPayUnionSplitModel::PAY_STATUS_OK)
                           ->groupBy('childTypeDesc')
                           ->when($engine == SeparateService::DB, function ($query) {
                               $query->select(DB::raw("sum(payPrice) as sumPayPrice"), DB::raw("count(*) as countPay"),
                                   'childTypeDesc');
                           })
                           ->when($engine == SeparateService::CLICKHOUSE, function ($query) {
                               $query->select(raw("sum(payPrice) as sumPayPrice"), raw("count(*) as countPay"),
                                   'childTypeDesc');
                           })
                           ->orderByDesc('countPay')
                           ->get()
                           ->map(function ($item) use ($listRefund) {
                               if (isset($listRefund[$item->childTypeDesc])) {
                                   $item->sumPayPrice = $item->sumPayPrice - ($listRefund[$item->childTypeDesc]['sumPayPrice'] ?? 0);
                               }
                               if (!$item->childTypeDesc) {
//                                   $item->childTypeDesc = OrderPayUnionSplitModel::PAY_TYPE_TEXT_NEW[$item->payType ?? 0] ?? "";

                                   $item->childTypeDesc = '';
                               }

                               return $item;
                           });

        $payObj = clone $obj;
        $payRes = $payObj->where('payStatus', OrderPayUnionSplitModel::PAY_STATUS_OK)
                         ->when($engine == SeparateService::DB, function ($query) {
                             $query->select(DB::raw("sum(payPrice) as sumPayPrice"), DB::raw("count(*) as countPay"));
                         })
                         ->when($engine == SeparateService::CLICKHOUSE, function ($query) {
                             $query->select(raw("sum(payPrice) as sumPayPrice"), raw("count(*) as countPay"));
                         })
                         ->get();

        $refundObj = clone $obj;
        $refundRes = $refundObj->where('payStatus', OrderPayUnionSplitModel::PAY_STATUS_REFUND)
                               ->when($engine == SeparateService::DB, function ($query) {
                                   $query->select(DB::raw("sum(payPrice) as sumPayPrice"),
                                       DB::raw("count(*) as countPay"));
                               })
                               ->when($engine == SeparateService::CLICKHOUSE, function ($query) {
                                   $query->select(raw("sum(payPrice) as sumPayPrice"), raw("count(*) as countPay"));
                               })
                               ->get();

        $total = [
            'sumPayPrice'    => $payRes[0]->sumPayPrice ?? 0,
            'countPay'       => $payRes[0]->countPay ?? 0,
            'sumRefundPrice' => $refundRes[0]->sumPayPrice ?? 0,
            'countRefund'    => $refundRes[0]->countPay ?? 0,
        ];
        return ['list' => $list, 'total' => $total];
    }


    // 分销订单
    protected function inDistributionOrderBase(): array
    {
        // 总订单
        $orderObjTotal = $this->getModelOrderObj(OrderMerchantEnum::ORDER_TYPE_DISTRIBUTION)
                              ->where('distributionId', '>', 0)
                              ->where('orderStatus', CodeEnum::ORDER_STATUS_FINISHED)
                              ->when($this->useEngine == SeparateService::DB, function ($query) {
                                  $query->select([DB::raw('count(1) as total')]);
                              })
                              ->when($this->useEngine == SeparateService::CLICKHOUSE, function ($query) {
                                  $query->select(raw("count(1) as total"));
                              })
                              ->first();
        // 非全额退款订单
        $orderObjSum = $this->getModelOrderObj(OrderMerchantEnum::ORDER_TYPE_DISTRIBUTION)
                            ->where('distributionId', '>', 0)
                            ->where('orderStatus', CodeEnum::ORDER_STATUS_FINISHED)
                            ->where('refundStatus', '!=', CodeEnum::ORDER_REFUND_STATUS_ALL)
                            ->when($this->useEngine == SeparateService::DB, function ($query) {
                                $query->select([
                                    DB::raw('sum(originalPrice) as sumOriginalPrice'),
                                    DB::raw('sum(realPayPrice) as sumRealPayPrice'),
                                    DB::raw('sum(realDiscountPrice) as sumDiscountPrice'),
                                    DB::raw('sum(distributionAmount) as sumDistributionAmount'),
                                    DB::raw('count(1) as total'),
                                ]);
                              })
                            ->when($this->useEngine == SeparateService::CLICKHOUSE, function ($query) {
                                $query->select([
                                    raw('sum(originalPrice) as sumOriginalPrice'),
                                    raw('sum(realPayPrice) as sumRealPayPrice'),
                                    raw('sum(realDiscountPrice) as sumDiscountPrice'),
                                    raw('sum(distributionAmount) as sumDistributionAmount'),
                                    raw('count(1) as total'),
                                ]);
                            })
                            ->first();

        // 合作中渠道数
        $channelCount = ShopDistributionModel::getCount($this->shopIds[0], ShopDistributionModel::STATUS_DEFAULT);

        // 活跃渠道数
        $activeChannelCount = $this->getModelOrderObj(OrderMerchantEnum::ORDER_TYPE_DISTRIBUTION)
                                   ->where('distributionId', '>', 0)
                                   ->where('orderStatus', CodeEnum::ORDER_STATUS_FINISHED)
                                   ->where('refundStatus', '!=', CodeEnum::ORDER_REFUND_STATUS_ALL)
                                   ->groupBy('distributionId')
                                   ->select('distributionId')
                                   ->get()
                                   ->count();

        // 退款订单
        $refundOrderObjSum = $this->getModelOrderObj(OrderMerchantEnum::ORDER_TYPE_DISTRIBUTION)
                                  ->where('distributionId', '>', 0)
                                  ->where('orderStatus', CodeEnum::ORDER_STATUS_FINISHED)
                                  ->whereIn('refundStatus',
                                      [CodeEnum::ORDER_REFUND_STATUS_PART, CodeEnum::ORDER_REFUND_STATUS_ALL])
                                  ->when($this->useEngine == SeparateService::DB, function ($query) {
                                      $query->select([
                                          DB::raw('sum(originalPrice) as sumOriginalPrice'),
                                          DB::raw('sum(refundMoney) as refundMoney'),
                                          DB::raw('count(1) as total'),
                                      ]);
                                  })
                                  ->when($this->useEngine == SeparateService::CLICKHOUSE, function ($query) {
                                      $query->select([
                                          raw('sum(originalPrice) as sumOriginalPrice'),
                                          raw('sum(refundMoney) as refundMoney'),
                                          raw('count(1) as total'),
                                      ]);
                                  })
                                  ->first();

        // 渠道营收排行
        $orderObjRank = $this->getModelOrderObj(OrderMerchantEnum::ORDER_TYPE_DISTRIBUTION)
                             ->where('distributionId', '>', 0)
                             ->where('orderStatus', CodeEnum::ORDER_STATUS_FINISHED)
                             ->where('refundStatus', '!=', CodeEnum::ORDER_REFUND_STATUS_ALL)
                             ->groupBy('distributionId')
                             ->when($this->useEngine == SeparateService::DB, function ($query) {
                                 $query->select([
                                     DB::raw('sum(realPayPrice) as sumRealPayPrice,distributionId'),

                                 ]);
                             })
                             ->when($this->useEngine == SeparateService::CLICKHOUSE, function ($query) {
                                 $query->select([
                                     raw('sum(realPayPrice) as sumRealPayPrice,distributionId'),
                                 ]);
                             })
                             ->get()->toArray();
        if ($orderObjRank) {
            $distributionIds  = array_column($orderObjRank, 'distributionId');
            $distributionInfo = ShopDistributionModel::query()
                                                     ->whereIn('id', $distributionIds)
                                                     ->get()
                                                     ->keyBy('id')->toArray();
            array_multisort(array_column($orderObjRank, 'sumRealPayPrice'), SORT_DESC, $orderObjRank);
            foreach ($orderObjRank as &$v) {
                if (isset($distributionInfo[$v['distributionId']])) {
                    $v['partnerName'] = $distributionInfo[$v['distributionId']]['partnerName'] ?? '';
                }
            }
        }

        return [
            'originPrice'        => $orderObjSum->sumOriginalPrice ?? 0,// 营业额
            'incomePrice'        => $orderObjSum->sumRealPayPrice ?? 0,  // 渠道收入
            'discountPrice'      => $orderObjSum->sumDiscountPrice ?? 0,// 优惠金额
            'orderCount'         => $orderObjSum->total ?? 0,   // 有效订单数
            'refundOrderCount'   => $refundOrderObjSum->total ?? 0,  // 退款订单
            'refundIncomePrice'  => $refundOrderObjSum->refundMoney ?? 0,  // 退款金额
            'brokerage'          => $orderObjSum->sumDistributionAmount ?? 0,// 总分佣金额
            'channelCount'       => $channelCount ?? 0,// 合作中渠道数
            'activeChannelCount' => $activeChannelCount ?? 0,// 活跃渠道数
            'rankData'           => $orderObjRank,
            'orderCountTotal'    => $orderObjTotal->total ?? 0,// 总订单数
        ];
    }

    // 店内分销订单列表
    protected function inDistributionOrderListsBase(int $pageSize, int $pageNum, int $distributionId): array
    {
        $orderObjTotal = $this->getModelOrderObj(OrderMerchantEnum::ORDER_TYPE_DISTRIBUTION)
                              ->where('distributionId', $distributionId)
                              ->where('orderStatus', CodeEnum::ORDER_STATUS_FINISHED)
                              ->select([
                                  DB::raw('sum(originalPrice) as sumOriginalPrice'),
                                  DB::raw('sum(realPayPrice) as sumRealPayPrice'),
                                  DB::raw('count(1) as total'),
                              ])
                              ->first();

        $originOrderObjSum = $this->getModelOrderObj(OrderMerchantEnum::ORDER_TYPE_DISTRIBUTION)
                                  ->where('distributionId', $distributionId)
                                  ->where('orderStatus', CodeEnum::ORDER_STATUS_FINISHED)
                                  ->where('refundStatus', '<>', CodeEnum::ORDER_REFUND_STATUS_ALL)
                                  ->select([
                                      DB::raw('sum(originalPrice) as sumOriginalPrice'),
                                      DB::raw('sum(realPayPrice) as sumRealPayPrice'),
                                      DB::raw('sum(distributionAmount) as sumDistributionAmount'),
                                      DB::raw('count(1) as total'),
                                  ])
                                  ->first();

        $refundOrderObjSum = $this->getModelOrderObj(OrderMerchantEnum::ORDER_TYPE_DISTRIBUTION)
                                  ->where('distributionId', $distributionId)
                                  ->where('orderStatus', CodeEnum::ORDER_STATUS_FINISHED)
                                  ->whereIn('refundStatus', [CodeEnum::ORDER_REFUND_STATUS_PART,CodeEnum::ORDER_REFUND_STATUS_ALL])
                                  ->select([
                                      DB::raw('sum(originalPrice) as sumOriginalPrice'),
                                      DB::raw('sum(refundMoney) as refundMoney'),
                                      DB::raw('count(1) as total'),
                                  ])
                                  ->first();

        $total = [
            'originPrice'       => $originOrderObjSum->sumOriginalPrice ?? 0,// 营业额
            'incomePrice'       => $originOrderObjSum->sumRealPayPrice ?? 0,// 收入
            'orderCount'        => $originOrderObjSum->total ?? 0,// 有效订单数
            'brokerage'         => $originOrderObjSum->sumDistributionAmount ?? 0,// 总分佣金额
            'ratio'             => 0,// 分佣比率
            'originPriceTotal'  => $orderObjTotal->sumOriginalPrice ?? 0,// 交易金额
            'orderCountTotal'   => $orderObjTotal->total ?? 0,// 总订单数
            'refundIncomePrice' => $refundOrderObjSum->refundMoney ?? 0,  // 退款金额
            'refundOrderCount'  => $refundOrderObjSum->total ?? 0, // 退款订单数
        ];

        $orderObj = $this->getModelOrderObj(OrderMerchantEnum::ORDER_TYPE_DISTRIBUTION)
                         ->where('distributionId', $distributionId)
                         ->where('orderStatus', CodeEnum::ORDER_STATUS_FINISHED)
                         ->orderByDesc('createdAt');

        $query = $orderObj->paginate($pageSize, ['*'], 'page', $pageNum);
        $lists = collect($query->items())->map(function ($item) {
            $item->timestamps = false;

            return [
                'orderId'            => (string)$item->orderId,
                'createdAt'          => date('Y-m-d H:i:s', $item->createdAt),
                'serialNum'          => str_pad($item->serialNum, CodeEnum::ORDER_LEADING_ZERO, "0", STR_PAD_LEFT),
                'orderStatusText'    => $item->orderStatusText,
                'payPrice'           => $item->realPayPrice,
                'distributionId'     => $item->distributionId,
                'distributionPer'    => $item->distributionPer,
                'distributionAmount' => $item->distributionAmount,
            ];
        });

        // 渠道详细
        $ShopDistribution           = ShopDistributionService::info($this->shopIds[0], $distributionId);

        $settlementCycleType = $ShopDistribution['settlementCycleType'] ?? 1;//结算周期 1:周,2:月
        if ($settlementCycleType == ShopDistributionModel::CYCLE_TYPE_WEEK) {
            $getDayInWeek  = ShopDistributionService::getDayInWeek(strtotime(date('Y-m-d', strtotime("-7 day"))));
            $lastStartTime = strtotime($getDayInWeek['startTime'] ?? "");
            $nowEndTime    = strtotime($getDayInWeek['endTime'] ?? "");
        } else {
            $lastStartTime = strtotime(date("Y-m-01", strtotime("-1 month")));
            $nowEndTime    = strtotime(date("Y-m-01")) - 1;
        }

        $ShopDistributionBrokerage = ShopDistributionBillRecordModel::getBillRecordByShopId($this->shopIds[0],
            $distributionId, $lastStartTime, $nowEndTime);

        // 最近修改比例时间
        $lastLog = OperateLogModel::getData(OperateLogModel::MODULE_DISTRIBUTION,
            OperateLogModel::BUSINESS_DISTRIBUTION_UPDATE_RATIO, $distributionId, 0, 'desc');
        if ($lastLog) {
            $lastUpdateRatioTime = $lastLog->createdAt->toDateTimeString();
        } else {
            $lastUpdateRatioTime = $ShopDistribution['createdAt'] ?? '';
        }

        $distributionInfo = [
            'partnerName'             => $ShopDistribution['partnerName'] ?? '',//合作方名称
            'ratio'                   => $ShopDistribution['ratio'] ?? 0,//分佣比例
            'settlementCycleType'     => $settlementCycleType,//结算周期 1:周,2:月
            'settlementCycleTypeText' => $ShopDistribution['settlementCycleTypeText'] ?? '',
            'lastMothBrokerage'       => $ShopDistributionBrokerage,//上个月分佣金额
            'lastUpdateRatioTime'     => $lastUpdateRatioTime,//最近修改比例时间
        ];
        $total['ratio']   = $distributionInfo['ratio'];

        return [
            'pageNum'          => $query->currentPage(),
            'pageSize'         => $query->perPage(),
            'pageCount'        => ceil($query->total() / $query->perPage()),
            'count'            => $query->total(),
            'lists'            => $lists,
            'total'            => $total,
            'distributionInfo' => $distributionInfo,
        ];
    }

    public function originalPriceBase(): array
    {
        $orderObj = $this->getModelOrderObj(OrderMerchantEnum::ORDER_TYPE_IN)
                         ->where('orderStatus', CodeEnum::ORDER_STATUS_FINISHED)
                         ->where('refundStatus', '!=', CodeEnum::ORDER_REFUND_STATUS_ALL)
                         ->when($this->useEngine == SeparateService::DB, function ($query) {
                             $query->select([
                                 DB::raw('sum(originalPrice) as sumOriginalPrice'),
                                 DB::raw('sum(realPayPrice) as sumRealPayPrice'),
                             ]);
                         })
                         ->when($this->useEngine == SeparateService::CLICKHOUSE, function ($query) {
                             $query->select([
                                 raw('sum(originalPrice) as sumOriginalPrice'),
                                 raw('sum(realPayPrice) as sumRealPayPrice'),
                             ]);
                         })
                         ->get()
                         ->first();

        $orderObjWaimai = $this->getModelOrderObj(OrderMerchantEnum::ORDER_TYPE_WAI_MAI)
                               ->where("orderStatus", '!=', WaiMaiDBEnum::ORDER_STATUS_7)
                               ->when($this->useEngine == SeparateService::DB, function ($query) {
                                   $query->select([
                                       DB::raw('sum(originalPrice)-sum(originalShippingPrice) as sumOriginalPrice'),
                                       DB::raw('sum(expectIncome) as sumExpectIncome'),
                                   ]);
                               })
                               ->when($this->useEngine == SeparateService::CLICKHOUSE, function ($query) {
                                   $query->select([
                                       raw('sum(originalPrice)-sum(originalShippingPrice) as sumOriginalPrice'),
                                       raw('sum(expectIncome) as sumExpectIncome'),
                                   ]);
                               })
                               ->get()
                               ->first();

        $originalPrice  = (int)$orderObj->sumOriginalPrice + (int)$orderObjWaimai->sumOriginalPrice;// 营业额
        $realPayPrice   = (int)$orderObj->sumRealPayPrice + (int)$orderObjWaimai->sumExpectIncome;// 营业收入
        return ['originalPrice' => $originalPrice, 'realPayPrice' => $realPayPrice];
    }
}
